package cnsatmsmart.automation.mmi.controller.client;

import cnsatmsmart.automation.mmi.controller.Buffer.Asterix21Data;
import cnsatmsmart.automation.mmi.controller.Buffer.Asterix21DataList;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Merupakan kelas client yang menerima data dari sender secara multicast
 * @author SIK - PTIK, BPPT
 */
public class ClientMulticastThread implements Runnable {
    /**
     * Port jaringan minimum
     */
    public static final int MIN_PORT = 1024;    
    /**
     * Port jaringan maksimum
     */
    public static final int MAX_PORT = 65535;   

    private Asterix21DataList Ax21DataList = null;
    private boolean ExitThread = false;
    private int Port;
    private String Group, BindInterface;

    /**
     * Konstruktor
     * @param ip IP group multicast
     * @param port Port
     * @param bindinterface Binding interface pada local machine
     * @param ax21 List dari data asterix yang akan digunakan untuk menampung data asterix dari server
     */
    public ClientMulticastThread(String ip, int port, String bindinterface, Asterix21DataList ax21)
    {
        this.Group = ip;
        this.Port = port;
        this.BindInterface = bindinterface;
        this.Ax21DataList = ax21;
    }

    /**
     * Keluar dari thread
     */
    public void Close()
    {
        this.ExitThread = true;
    }

    public void run() {
        InetAddress mcAddress = null;
        InetAddress bindif = null;
        
        try {
            mcAddress = InetAddress.getByName(Group);
            bindif = InetAddress.getByName(BindInterface);
        } catch (UnknownHostException ex) {
            Logger.getLogger(ClientMulticastThread.class.getName()).log(Level.SEVERE, null, ex);
            ExitThread = true;
        }

        MulticastSocket mSocket = null;
        try {
            //Instansiasi multicast socket
            mSocket = new MulticastSocket(Port);
            //Set binding interface
            if (bindif != null) mSocket.setInterface(bindif);
            //Set the address reuse option
            mSocket.setReuseAddress(true);  //Java 1.4 and higher
            //Join multicast group
            mSocket.joinGroup(mcAddress);
        } catch (IOException ex) {
            Logger.getLogger(ClientMulticastThread.class.getName()).log(Level.SEVERE, null, ex);
        }

        short cat, length1, length2;
        short[] arrdata;
        int bufferLen;
        byte[] buf;
        DatagramPacket packet;

	while(!ExitThread){
            //Membuat datagrampacket dengan buffer yang masih kosong
            arrdata = new short[4096];
            buf = new byte[4096];
            packet = new DatagramPacket(buf, buf.length);

            try {
                //Client akan terus menunggu untuke menerima instans datagram packet
                mSocket.receive(packet);
            } catch (IOException ex) {
                Logger.getLogger(ClientMulticastThread.class.getName()).log(Level.SEVERE, null, ex);
            }

            //Packet yang diterima disimpan dalam buffer
            buf = packet.getData();

            //Data dalam buffer kemudian dipilah - pilah untuk dimasukan ke variabel cat, length1, length2, dan arrdata
            cat = (short)(buf[0] & 0x00FF);
            length1 = (short) (buf[1] & 0x00FF);
            length2 = (short) (buf[2] & 0x00FF);
            bufferLen = 256 * length1 + length2;

            for (int i = 0; i < bufferLen - 3; i++)
            {
                arrdata[i] = (short) (buf[i+3] & 0x00FF);
            }

            if (buf != null)
            {
                //Data yang sudah dipilah - pilah kemudian di masukan sebagai Asterix21Data ke Asterix21DataList
                Asterix21Data ax21 = new Asterix21Data(cat, length1, length2, arrdata, bufferLen);
                Ax21DataList.AddAx21Data(ax21);
            }
	}

        try {
            mSocket.leaveGroup(mcAddress);
            mSocket.close();
        } catch (IOException ex) {
            Logger.getLogger(ClientMulticastThread.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
